#include "blockq.h"
#include <func.h>

BlockQ* blockq_create(void){
	BlockQ* q = (BlockQ*) malloc(sizeof(BlockQ));

	q->front = 0;
	q->rear = 0;
	q->size = 0;
	pthread_mutex_init(&q->mutex,NULL);
	pthread_cond_init(&q->not_full,NULL);
	pthread_cond_init(&q->not_empty,NULL);
	
	return q;
}

void blockq_destroy(BlockQ* q) {
	
	 pthread_mutex_destroy(&q->mutex); 
	pthread_cond_destroy(&q->not_full);
	pthread_cond_destroy(&q->not_empty);
	free(q);
}

bool blockq_empty(BlockQ* q){
	pthread_mutex_lock(&q->mutex);
	int sz = q->size;
	pthread_mutex_unlock(&q->mutex);
	return sz == 0;
}

bool blockq_full(BlockQ* q){
	pthread_mutex_lock(&q->mutex);
	int sz = q->size;
	pthread_mutex_unlock(&q->mutex);
	return sz == N; 
}

void blockq_push(BlockQ* q, E val){
	pthread_mutex_lock(&q->mutex);
	while(q->size == N){
		//not_full条件不成立 生产者等待队列不满 陷入阻塞
		//调用pthread_cond_wait()函数
		//1.释放q->mutex
		//2.陷入阻塞
		//
		pthread_cond_wait(&q->not_full,&q->mutex);
		//传入的是地址修改条件变量 里面含有一个队列包含陷入阻塞的线程的id号
		//且该条件变量的状态也会被修改 
		//3.到这里 表示别唤醒重新获得了q.mutex;
		//not_full 现在成不成立是不知道的 表示这个条件曾经成立过
		//需要重新判断
	}
	//到这里q.size !=N
	//执行添加操作
	q->elements[q->rear] = val;
	q->rear = (q->rear + 1) % N;
	q->size++;
	//此时添加了元素队列一定不为空
	//唤醒消费者
	pthread_cond_broadcast(&q->not_empty);

	//释放锁
	pthread_mutex_unlock(&q->mutex);
}

E blockq_pop(BlockQ* q){
	pthread_mutex_lock(&q->mutex);
	while(q->size == 0){
		pthread_cond_wait(&q->not_empty,&q->mutex);//将互斥锁释放掉
	}

	//not_empty 成立
	E val = q->elements[q->front];
	q->front = (q->front +1)%N;
	q->size--;
	pthread_cond_broadcast(&q->not_full);

	pthread_mutex_unlock(&q->mutex);

	return val;
}

E block_peek(BlockQ* q){
	pthread_mutex_lock(&q->mutex);
	
	while(q->size==0){
		pthread_cond_wait(&q->not_empty,&q->mutex);
	}

	E val = q->elements[q->front];
	pthread_mutex_unlock(&q->mutex);
	return val;
}
